import { Component, OnDestroy, OnInit } from '@angular/core';
import * as echarts from 'echarts';
import { NzMessageService } from 'ng-zorro-antd/message';

import ControlLimitCoefficient from '../../../assets/ControlLimitCoefficient.json';
import { ChartConfigurationService } from '../../chart-configuration.service';
import { DataSourceService } from '../../data-source.service';
import { SpcChartAbnormalJudgement, pointDataCollect, List } from '../occ-rules/occrules';

@Component({
  selector: 'app-xbar-mr',
  templateUrl: './xbar-mr.component.html',
  styleUrls: ['./xbar-mr.component.less']
})
export class XbarMrComponent implements OnInit, OnDestroy {
  meanYdata: any = [];
  meanXdata: any = [];
  meanUclPoint: number = 0;
  meanClPoint: number = 0;
  meanLclPoint: number = 0;
  meanSigmaPoint: number = 0;
  meanSigmaLPoint: number = 0;
  meanYMin: number = 0;
  meanYMax: number = 0;
  meanUSpecLine: number = 0;
  meanLSpecLine: number = 0;
  customSpecLineType: number = 0; // 0:未制定自定义规格线   1：上下规格线都指定  2：只制定上规格线  3：只制定下规格线

  rangeYdata: any = [];
  movingRangeData: any = [];
  rangeXdata: any = [];
  rangeUclPoint: number = 0;
  rangeClPoint: number = 0;
  rangeLclPoint: number = 0;
  rangeSigmaPoint: number = 0;
  rangeSigmaLPoint: number = 0;
  rangeYMin: number = 0;
  rangeYMax: number = 0;

  singleResultCollectLength: number = 0;
  chartViewPrecision: number = 4;
  numberOfMovingRangeSteps: number = 2;

  E2: number = 0;
  D3: number = 0;
  D4: number = 0;
  d2: number = 0;

  singePointcP: number = 0;
  singePointcA: number = 0;
  singePointcPk: number = 0;
  singePointpP: number = 0;
  singePointpPK: number = 0;

  tableDataSourceCollection: any = []; // table is used to display data sources
  DataSource: any = []; // data origin
  resultDataCollection: any = []; // Set of all data points
  processPerSingMaArray: any = []; // process Performance SingMa , Useing pP , pPK

  setDrawingFrequency: number = 2000; // Plot to obtain data frequency
  xScroll: number = 100;
  intervalId: any;

  rules: number = 0;
  chartViewPoints: number = 0;
  dataSourcePoints: number = 0;
  randomMin: number = 0;
  randomMax: number = 0;
  dataSourceValues: any = [];
  numbersCount: number = 0;
  moveIndexCount: number = 0;
  firstTime: boolean = true;
  formMeanUSpecLine: string = '';
  formMeanLSpecLine: string = '';

  meanSigmaBCOverCL: number = 0;
  meanSigmaABOverCL: number = 0;
  meanSigmaBCBelowCL: number = 0;
  meanSigmaABBelowCL: number = 0;

  rangeSigmaBCOverCL: number = 0;
  rangeSigmaABOverCL: number = 0;
  rangeSigmaBCBelowCL: number = 0;
  rangeSigmaABBelowCL: number = 0;

  constructor(
    private chartCfgSrv: ChartConfigurationService,
    private dataSourceSrv: DataSourceService,
    private messageSrv: NzMessageService
  ) {
    this.singleResultCollectLength = this.dataSourceSrv.getSampleResultData(this.chartCfgSrv.getChartType(), 0)[0]?.Result.length;
    this.numberOfMovingRangeSteps = this.chartCfgSrv.getNumberOfMovingRangeSteps();
    this.D3 = ControlLimitCoefficient.find(a => a.n == this.numberOfMovingRangeSteps)?.coefficient.D3 as number;
    this.D4 = ControlLimitCoefficient.find(a => a.n == this.numberOfMovingRangeSteps)?.coefficient.D4 as number;
    this.d2 = ControlLimitCoefficient.find(a => a.n == this.numberOfMovingRangeSteps)?.coefficient.d2 as number;
    this.E2 = parseFloat((3 / this.d2).toFixed(this.chartViewPrecision));
  }

  ec = echarts as any;

  cleanData(): void {
    this.meanYdata.length = 0;
    this.meanUclPoint = 0;
    this.meanClPoint = 0;
    this.meanLclPoint = 0;
    this.meanSigmaPoint = 0;
    this.meanSigmaLPoint = 0;
    this.meanYMax = 0;
    this.meanYMin = 0;

    this.rangeYdata.length = 0;
    this.movingRangeData.length = 0;
    this.rangeUclPoint = 0;
    this.rangeClPoint = 0;
    this.rangeLclPoint = 0;
    this.rangeSigmaPoint = 0;
    this.rangeSigmaLPoint = 0;
    this.rangeYMin = 0;
    this.rangeYMax = 0;

    this.resultDataCollection.length = 0;
    this.processPerSingMaArray.length = 0;
  }

  onSetmedianSpecLine(): void {
    this.meanUSpecLine = parseFloat(this.formMeanUSpecLine);
    this.meanLSpecLine = parseFloat(this.formMeanLSpecLine);

    if (this.meanUSpecLine > 0 && this.meanLSpecLine > 0 && this.meanLSpecLine >= this.meanUSpecLine) {
      this.messageSrv.error('上规格线必须大于下规格线 或 值不能相同');
      this.formMeanUSpecLine = this.formMeanLSpecLine = '';
      this.meanUSpecLine = this.meanLSpecLine = 0;
    } else {
      if (this.meanUSpecLine && this.meanLSpecLine) {
        this.customSpecLineType = 1;
      } else if (this.meanUSpecLine && !this.meanLSpecLine) {
        this.customSpecLineType = 2;
      } else if (!this.meanUSpecLine && this.meanLSpecLine) {
        this.customSpecLineType = 3;
      } else if (!this.meanUSpecLine && !this.meanLSpecLine) {
        this.customSpecLineType = 0;
      }
    }
  }

  randomData(timenum: number): string {
    let myDate = new Date();
    myDate = new Date(myDate.setSeconds(myDate.getSeconds() + timenum));
    let date = `${myDate.getMinutes()}:${myDate.getSeconds()}`;
    return date;
  }

  loadChartConfig(): void {
    this.rules = this.chartCfgSrv.getChartRules();
    this.setDrawingFrequency = this.chartCfgSrv.getChartSampleTimeInterval() * 1000;
    this.chartViewPoints = this.chartCfgSrv.getChartPoints();
    this.chartViewPrecision = this.chartCfgSrv.getChartViewPrecision();

    if (this.chartViewPoints > 15) this.xScroll = this.xScroll + Math.ceil((this.chartViewPoints - 15) / 5) * 50;

    this.dataSourcePoints = this.dataSourceSrv.getChartLength(this.chartCfgSrv.getChartType());
    this.randomMin = this.dataSourceSrv.getRandomMin();
    this.randomMax = this.dataSourceSrv.getRandomMax();

    for (var i = 0; i < this.dataSourcePoints; i++) {
      this.dataSourceValues[i] = this.dataSourceSrv.getSampleResultData(this.chartCfgSrv.getChartType(), 0)[i];
    }
  }

  getRandomDataSource(min: number, max: number): number {
    var value = parseFloat((Math.random() * (max - min) + min).toFixed(2));
    return value;
  }

  updateDataSourceValues(): void {
    var i: number = 0;
    var randomValue: number = 0;
    if (this.numbersCount < this.chartViewPoints) {
      if (this.numbersCount < this.dataSourcePoints) {
        this.DataSource[this.numbersCount] = this.dataSourceValues[this.numbersCount];
      } else {
        for (var i = 0; i < this.dataSourceValues[0].Result.length; i++) {
          randomValue = this.getRandomDataSource(this.randomMin, this.randomMax);
          this.DataSource[this.numbersCount].Result[i] = randomValue;
        }
      }

      this.numbersCount++;
    } else {
      if (this.numbersCount < this.dataSourcePoints) {
        this.DataSource.shift();
        this.DataSource.push(this.dataSourceValues[this.numbersCount]);
      } else {
        this.DataSource.shift();
        let list_result = { SampleID: this.numbersCount + 1, Result: [] } as any;
        for (var j = 0; j < this.dataSourceValues[0].Result.length; j++) {
          randomValue = this.getRandomDataSource(this.randomMin, this.randomMax);
          list_result.Result.push(randomValue);
        }
        this.DataSource.push(list_result);
      }
      this.numbersCount++;
    }
  }

  ngOnDestroy(): void {
    clearInterval(this.intervalId);
  }

  ngOnInit() {
    this.loadChartConfig();
    this.intervalId = setInterval(() => {
      this.cleanData();
      this.updateDataSourceValues();
      this.GetPointData();

      let sumMean = 0;
      for (let i = 0; i < this.meanYdata.length; i++) {
        sumMean += this.meanYdata[i];
      }
      let sumMovingRange = 0;
      for (let i = 0; i < this.movingRangeData.length; i++) {
        sumMovingRange += this.movingRangeData[i];
      }

      let averageYData = sumMean / this.meanYdata.length;
      if (this.meanYdata.length < this.numberOfMovingRangeSteps) {
        this.meanUclPoint = parseFloat(averageYData.toFixed(this.chartViewPrecision));
        this.meanClPoint = parseFloat(averageYData.toFixed(this.chartViewPrecision));
        this.meanLclPoint = parseFloat(averageYData.toFixed(this.chartViewPrecision));
      } else {
        let averageR = sumMovingRange / (this.meanYdata.length - this.numberOfMovingRangeSteps + 1);
        this.meanUclPoint = parseFloat((averageYData + this.E2 * averageR).toFixed(this.chartViewPrecision));
        this.meanClPoint = parseFloat(averageYData.toFixed(this.chartViewPrecision));
        this.meanLclPoint = parseFloat((averageYData - this.E2 * averageR).toFixed(this.chartViewPrecision));
        this.rangeUclPoint = this.D4 * averageR;
        this.rangeClPoint = averageR;
        this.rangeLclPoint = this.D3 * averageR;
      }

      //#region get sigma line value
      this.meanSigmaPoint = parseFloat(((this.meanUclPoint - this.meanClPoint) / 3).toFixed(this.chartViewPrecision));
      this.meanSigmaLPoint = parseFloat(((this.meanClPoint - this.meanLclPoint) / 3).toFixed(this.chartViewPrecision));
      this.rangeSigmaPoint = parseFloat(((this.rangeUclPoint - this.rangeClPoint) / 3).toFixed(this.chartViewPrecision));
      this.rangeSigmaLPoint = parseFloat(((this.rangeClPoint - this.rangeLclPoint) / 3).toFixed(this.chartViewPrecision));
      //#endregion

      //#region Determine the Y-axis coordinate
      let MeanValue = parseFloat(
        ((Math.max.apply(null, this.meanYdata) - Math.min.apply(null, this.meanYdata)) / 2).toFixed(this.chartViewPrecision)
      );
      let MeanMaxPoint = [Math.max.apply(null, this.meanYdata), this.meanUclPoint];
      let MeanMinPoint = [Math.min.apply(null, this.meanYdata), this.meanLclPoint];
      if (this.meanUSpecLine > 0) {
        MeanMaxPoint.push(this.meanUSpecLine);
      }
      if (this.meanLSpecLine > 0) {
        MeanMinPoint.push(this.meanLSpecLine);
      }

      this.meanYMax = parseFloat((Math.max.apply(null, MeanMaxPoint) + MeanValue).toFixed(this.chartViewPrecision));
      this.meanYMin = parseFloat((Math.min.apply(null, MeanMinPoint) - MeanValue).toFixed(this.chartViewPrecision));
      if (this.meanYMax == this.meanUclPoint) {
        this.meanYMax =
          this.meanYMax +
          (Math.min.apply(null, MeanMinPoint) > 1 ? Math.min.apply(null, MeanMinPoint) / 10 : Math.min.apply(null, MeanMinPoint));
      }
      // this.meanYMin = parseFloat((this.meanYMax - 2 * parseFloat(((Math.max.apply(null, this.meanYdata) - Math.min.apply(null, this.meanYdata))).toFixed(this.chartViewPrecision))).toFixed(this.chartViewPrecision));

      let RangeMaxPoint = [Math.max.apply(null, this.rangeYdata), this.rangeUclPoint];
      this.rangeYMax = parseFloat(
        (Math.max.apply(null, RangeMaxPoint) + (Math.max.apply(null, this.rangeYdata) - Math.min.apply(null, this.rangeYdata)) / 2).toFixed(
          this.chartViewPrecision
        )
      );
      if (this.rangeYMax == this.rangeUclPoint) {
        this.rangeYMax =
          this.rangeYMax +
          (Math.min.apply(null, this.rangeYdata) > 1 ? Math.min.apply(null, this.rangeYdata) / 5 : Math.min.apply(null, this.rangeYdata));
      }
      this.rangeYMin = 0;
      //#endregion

      //#region  The exception handling judgment rule, and the corresponding point in the figure is shown in red
      let meanUnormList = SpcChartAbnormalJudgement(
        this.meanUclPoint,
        this.meanLclPoint,
        this.meanClPoint,
        this.meanSigmaPoint,
        this.meanYdata,
        this.rules,
        this.meanSigmaLPoint
      ) as any;
      for (let item of meanUnormList.arr) {
        this.meanYdata[item.pointIndex] = {
          value: item.value,
          itemStyle: { color: 'rgba(211, 33, 33, 1)' },
          symbol: 'diamond',
          symbolSize: 15
        };
      }

      let rangeUnormList = SpcChartAbnormalJudgement(
        this.rangeUclPoint,
        this.rangeLclPoint,
        this.rangeClPoint,
        this.rangeSigmaPoint,
        this.rangeYdata,
        this.rules,
        this.rangeSigmaLPoint
      ) as any;
      for (let item of rangeUnormList.arr) {
        this.rangeYdata[item.pointIndex] = {
          value: item.value,
          itemStyle: { color: 'rgba(211, 33, 33, 1)' },
          symbol: 'diamond',
          symbolSize: 15
        };
      }
      //#endregion
      this.calculateSigmaLines();
      this.updateData();

      // if (this.meanYdata.length == 25) {
      //   clearInterval(this.intervalId);
      // }
    }, this.setDrawingFrequency);
  }

  calculateSigmaLines() {
    this.meanSigmaBCOverCL = this.meanClPoint + this.meanSigmaPoint;
    this.meanSigmaABOverCL = this.meanClPoint + this.meanSigmaPoint * 2;
    this.meanSigmaABBelowCL = this.meanClPoint - this.meanSigmaPoint * 2;
    this.meanSigmaBCBelowCL = this.meanClPoint - this.meanSigmaPoint;

    this.rangeSigmaBCOverCL = this.rangeClPoint + this.rangeSigmaPoint;
    this.rangeSigmaABOverCL = this.rangeClPoint + this.rangeSigmaPoint * 2;
    this.rangeSigmaABBelowCL = this.rangeClPoint - this.rangeSigmaLPoint * 2;
    this.rangeSigmaBCBelowCL = this.rangeClPoint - this.rangeSigmaLPoint;
  }

  tableDataShow(): void {
    let list_pointDataCollect = new List<pointDataCollect>();
    for (let i = 0; i < this.singleResultCollectLength; i++) {
      let m_pointDataCollect = new pointDataCollect();
      m_pointDataCollect.attribute = (i + 1).toString();

      for (let j = 0; j < this.DataSource?.length; j++) {
        m_pointDataCollect.result.push(parseFloat(this.DataSource[j].Result[i]));
      }
      list_pointDataCollect.Add(m_pointDataCollect);
    }
    this.tableDataSourceCollection = list_pointDataCollect;
  }

  GetPointData(): void {
    let xAixsIndex: number = 0;
    this.moveIndexCount++;
    if (this.firstTime) {
      let date = this.randomData(0);
      for (xAixsIndex = 0; xAixsIndex < this.chartViewPoints; xAixsIndex++) {
        if (xAixsIndex == 0) {
          this.meanXdata.push(date);
          this.rangeXdata.push(date);
        } else {
          date = this.randomData((this.setDrawingFrequency / 1000) * xAixsIndex);
          this.meanXdata.push(date);
          this.rangeXdata.push(date);
        }
      }
      this.firstTime = false;
    } else if (this.moveIndexCount > this.chartViewPoints) {
      this.meanXdata.shift();
      this.rangeXdata.shift();
      let date = this.randomData(0);
      this.meanXdata.push(date);
      this.rangeXdata.push(date);
    }

    this.tableDataShow();

    let thIndex_pointDataCollect = new pointDataCollect();
    let sum_pointDataCollect = new pointDataCollect();
    let range_pointDataCollect = new pointDataCollect();
    let avevage_pointDataCollect = new pointDataCollect();
    let cA_pointDataCollect = new pointDataCollect();
    let cP_pointDataCollect = new pointDataCollect();
    let cPK_pointDataCollect = new pointDataCollect();
    let pP_pointDataCollect = new pointDataCollect();
    let pPK_pointDataCollect = new pointDataCollect();

    thIndex_pointDataCollect.attribute = 'thIndex';
    sum_pointDataCollect.attribute = 'Sum';
    range_pointDataCollect.attribute = 'MR';
    avevage_pointDataCollect.attribute = 'Ave';
    cA_pointDataCollect.attribute = 'Ca';
    cP_pointDataCollect.attribute = 'Cp';
    cPK_pointDataCollect.attribute = 'Cpk';
    pP_pointDataCollect.attribute = 'Pp';
    pPK_pointDataCollect.attribute = 'Ppk';
    for (let i = 0; i < this.DataSource?.length; i++) {
      thIndex_pointDataCollect.result.push(this.DataSource[i].SampleID);
      let pointQuadraticSum = 0,
        pointSumQuadratic = 0;
      let X = 0;

      for (let j = 0; j < this.singleResultCollectLength; j++) {
        X += parseFloat(this.DataSource[i].Result[j]);
        this.resultDataCollection.push(this.DataSource[i].Result[j]);
      }

      sum_pointDataCollect.result.push(X.toFixed(this.chartViewPrecision));

      avevage_pointDataCollect.result.push((X / this.singleResultCollectLength).toFixed(this.chartViewPrecision));

      let processPerValue = JSON.parse(
        this.getProcessPerformanceCollectionValue(
          this.resultDataCollection.length,
          this.resultDataCollection,
          pointQuadraticSum,
          pointSumQuadratic
        )
      );
      let singleProcessPerSingMa =
        this.resultDataCollection.length == 1
          ? 0
          : parseFloat(
              Math.sqrt(
                (processPerValue.pointQuadraticSum - processPerValue.pointSumQuadratic / this.resultDataCollection.length) /
                  (this.resultDataCollection.length - 1)
              ).toFixed(this.chartViewPrecision)
            );
      this.processPerSingMaArray.push(singleProcessPerSingMa);

      let movingRange = 0;
      if (i >= this.numberOfMovingRangeSteps - 1) {
        let currentArray: number[] = [];
        for (let k = i - this.numberOfMovingRangeSteps + 1; k <= i; k++) {
          currentArray.push(this.DataSource[k].Result[0]);
        }
        let currentMax = Math.max(...currentArray);
        let currentMin = Math.min(...currentArray);
        movingRange = parseFloat((currentMax - currentMin).toFixed(this.chartViewPrecision));

        this.rangeYdata.push(movingRange);
        range_pointDataCollect.result.push(movingRange);
      } else {
        this.rangeYdata.push(null);
        range_pointDataCollect.result.push('-');
      }
      this.movingRangeData.push(movingRange);

      this.meanYdata.push(parseFloat((X / this.singleResultCollectLength).toFixed(this.chartViewPrecision)));
    }

    //#region  get cp,ca,cpk,pp,ppk single point data collection
    let cAValue: number = 0;
    for (let z = 0; z < this.numberOfMovingRangeSteps - 1; z++) {
      cP_pointDataCollect.result.push('-');
      cA_pointDataCollect.result.push('-');
      pP_pointDataCollect.result.push('-');
      cPK_pointDataCollect.result.push('-');
      pPK_pointDataCollect.result.push('-');
    }

    for (let z = this.numberOfMovingRangeSteps - 1; z < this.movingRangeData.length; z++) {
      let rangeValue =
        this.getProcessCapabilityCollectionValue(z + 1, this.movingRangeData, cAValue) / (z + 1 - (this.numberOfMovingRangeSteps - 1));
      let singleResultCollectionAvevage =
        this.getProcessCapabilityCollectionValue(z + 1, avevage_pointDataCollect.result, cAValue) / (z + 1);
      let pCSingma = parseFloat((rangeValue / this.d2).toFixed(this.chartViewPrecision));
      if (this.customSpecLineType === 0) {
        cP_pointDataCollect.result.push('-');
        cA_pointDataCollect.result.push('-');
        pP_pointDataCollect.result.push('-');
        cPK_pointDataCollect.result.push('-');
        pPK_pointDataCollect.result.push('-');
      } else {
        if (this.customSpecLineType === 1) {
          this.singePointcP =
            pCSingma == 0 ? 0 : parseFloat(((this.meanUSpecLine - this.meanLSpecLine) / (6 * pCSingma)).toFixed(this.chartViewPrecision));
          cP_pointDataCollect.result.push(this.singePointcP);
          this.singePointcA = parseFloat(
            (
              Math.abs((this.meanUSpecLine + this.meanLSpecLine) / 2 - singleResultCollectionAvevage) /
              ((this.meanUSpecLine - this.meanLSpecLine) / 2)
            ).toFixed(this.chartViewPrecision)
          );
          cA_pointDataCollect.result.push(this.singePointcA);

          this.singePointpP =
            this.processPerSingMaArray[z] == 0
              ? 0
              : parseFloat(
                  ((this.meanUSpecLine - this.meanLSpecLine) / (6 * this.processPerSingMaArray[z])).toFixed(this.chartViewPrecision)
                );
          pP_pointDataCollect.result.push(this.singePointpP);
        } else if (this.customSpecLineType === 2) {
          this.singePointcP =
            pCSingma == 0
              ? 0
              : parseFloat(((this.meanUSpecLine - singleResultCollectionAvevage) / (3 * pCSingma)).toFixed(this.chartViewPrecision));
          cP_pointDataCollect.result.push(this.singePointcP);
          this.singePointcA = 0;
          cA_pointDataCollect.result.push('-');

          this.singePointpP =
            this.processPerSingMaArray[z] == 0
              ? 0
              : parseFloat(
                  ((this.meanUSpecLine - singleResultCollectionAvevage) / (3 * this.processPerSingMaArray[z])).toFixed(
                    this.chartViewPrecision
                  )
                );
          pP_pointDataCollect.result.push(this.singePointpP);
        } else if (this.customSpecLineType === 3) {
          this.singePointcP =
            pCSingma == 0
              ? 0
              : parseFloat(((singleResultCollectionAvevage - this.meanLSpecLine) / (3 * pCSingma)).toFixed(this.chartViewPrecision));
          cP_pointDataCollect.result.push(this.singePointcP);
          this.singePointcA = 0;
          cA_pointDataCollect.result.push('-');

          this.singePointpP =
            this.processPerSingMaArray[z] == 0
              ? 0
              : parseFloat(
                  ((singleResultCollectionAvevage - this.meanLSpecLine) / (3 * this.processPerSingMaArray[z])).toFixed(
                    this.chartViewPrecision
                  )
                );
          pP_pointDataCollect.result.push(this.singePointpP);
        }
        cAValue = 0;
        this.singePointcPk = parseFloat(((1 - this.singePointcA) * this.singePointcP).toFixed(this.chartViewPrecision));
        cPK_pointDataCollect.result.push(this.singePointcPk);

        this.singePointpPK = parseFloat(((1 - this.singePointcA) * this.singePointpP).toFixed(this.chartViewPrecision));
        pPK_pointDataCollect.result.push(this.singePointpPK);
      }
    }
    //#endregion

    this.tableDataSourceCollection.Add(thIndex_pointDataCollect);
    this.tableDataSourceCollection.Add(sum_pointDataCollect);
    this.tableDataSourceCollection.Add(range_pointDataCollect);
    this.tableDataSourceCollection.Add(avevage_pointDataCollect);
    this.tableDataSourceCollection.Add(cA_pointDataCollect);
    this.tableDataSourceCollection.Add(cP_pointDataCollect);
    this.tableDataSourceCollection.Add(cPK_pointDataCollect);
    this.tableDataSourceCollection.Add(pP_pointDataCollect);
    this.tableDataSourceCollection.Add(pPK_pointDataCollect);
  }

  //#region get process capability  Used for cA, cP, cPK calculation
  getProcessCapabilityCollectionValue(index: number, result: any, cAValue: number): number {
    if (index <= 0) {
      return cAValue;
    }

    cAValue += parseFloat(result[index - 1]);
    return this.getProcessCapabilityCollectionValue(index - 1, result, cAValue);
  }
  //#endregion

  //#region get process Performance  Used for pP, pPK calculation
  getProcessPerformanceCollectionValue(index: number, result: any, pointQuadraticSum: number, pointSumQuadratic: number): string {
    if (index <= 0) {
      return `{ "pointQuadraticSum": "${pointQuadraticSum}", "pointSumQuadratic": "${Math.pow(pointSumQuadratic, 2)}" }`;
    }

    pointQuadraticSum += Math.pow(parseFloat(result[index - 1]), 2);
    pointSumQuadratic += parseFloat(result[index - 1]);
    return this.getProcessPerformanceCollectionValue(index - 1, result, pointQuadraticSum, pointSumQuadratic);
  }
  //#endregion

  updateData(): void {
    this.meanInitCharts();
    this.rangeInitCharts();
  }

  meanInitCharts(): void {
    const chartViewPrecisionMean = this.chartViewPrecision;
    const lineChart = this.ec.init(document.getElementById('lineChartMean'));
    const lineChartOption = {
      tooltip: {
        trigger: 'axis'
      },
      splitLine: {
        show: true
      },
      toolbox: {
        show: true
      },
      legend: {
        padding: 0
      },
      xAxis: [
        {
          type: 'category',
          data: this.meanXdata,
          axisLabel: {
            interval: 0,
            formatter: function (value: any, index: any) {
              if (index % 2 != 0) {
                return `\n\n${value}`;
              } else {
                return value;
              }
            }
          },
          name: '',
          splitLine: {
            show: false,
            lineStyle: {
              type: 'dashed'
            }
          },
          axisLine: {
            show: true,
            symbol: ['none', 'arrow'],
            symbolOffset: 10
          },
          nameTextStyle: {
            fontWeight: 600,
            fontSize: 18
          }
        }
      ],
      yAxis: [
        {
          type: 'value',
          name: 'Mean',
          splitLine: {
            show: false,
            lineStyle: {
              type: 'dashed'
            }
          },
          axisLine: {
            show: true,
            symbol: ['none', 'arrow'],
            symbolOffset: 10
          },
          axisLabel: {
            fontSize: 13,
            formatter: function (value: any, index: number) {
              return value.toFixed(chartViewPrecisionMean);
            }
          },
          min: this.meanYMin,
          max: this.meanYMax,
          scale: true,
          nameTextStyle: {
            fontWeight: 600,
            fontSize: 18
          }
        }
      ],
      series: [
        {
          name: '',
          showSymbol: true,
          data: this.meanYdata,
          type: 'line',
          markLine: {
            symbol: 'none',
            lineStyle: {
              normal: {
                type: 'solid'
              }
            },
            data: [
              {
                yAxis: this.meanLclPoint,
                name: 'min',
                lineStyle: {
                  color: '#8A2BE2'
                },
                label: {
                  normal: {
                    formatter: `${this.meanLclPoint.toFixed(chartViewPrecisionMean)}(LCL)`
                  }
                }
              },
              {
                yAxis: this.meanClPoint,
                name: 'target',
                lineStyle: {
                  color: '#00FF00'
                },
                label: {
                  normal: {
                    formatter: `${this.meanClPoint.toFixed(chartViewPrecisionMean)}(CL)`
                  }
                }
              },
              {
                yAxis: this.meanUclPoint,
                name: 'max',
                lineStyle: {
                  color: '#8A2BE2'
                },
                label: {
                  normal: {
                    formatter: `${this.meanUclPoint.toFixed(chartViewPrecisionMean)}(UCL)`
                  }
                }
              }
            ]
          }
        }
      ]
    };

    const sigmaLineChartOption = {
      tooltip: {
        trigger: 'axis'
      },
      splitLine: {
        show: true
      },
      toolbox: {
        show: true
      },
      legend: {
        padding: 0
      },
      xAxis: [
        {
          type: 'category',
          data: this.meanXdata,
          axisLabel: {
            interval: 0,
            formatter: function (value: any, index: any) {
              if (index % 2 != 0) {
                return `\n\n${value}`;
              } else {
                return value;
              }
            }
          },
          name: '',
          splitLine: {
            show: false,
            lineStyle: {
              type: 'dashed'
            }
          },
          axisLine: {
            show: true,
            symbol: ['none', 'arrow'],
            symbolOffset: 10
          },
          nameTextStyle: {
            fontWeight: 600,
            fontSize: 18
          }
        }
      ],
      yAxis: [
        {
          type: 'value',
          name: 'Mean',
          splitLine: {
            show: false,
            lineStyle: {
              type: 'dashed'
            }
          },
          axisLine: {
            show: true,
            symbol: ['none', 'arrow'],
            symbolOffset: 10
          },
          axisLabel: {
            fontSize: 13,
            formatter: function (value: any, index: number) {
              return value.toFixed(chartViewPrecisionMean);
            }
          },
          min: this.meanYMin,
          max: this.meanYMax,
          scale: true,
          nameTextStyle: {
            fontWeight: 600,
            fontSize: 18
          }
        }
      ],
      series: [
        {
          name: '',
          showSymbol: true,
          data: this.meanYdata,
          type: 'line',
          markLine: {
            symbol: 'none',
            lineStyle: {
              normal: {
                type: 'solid'
              }
            },
            data: [
              {
                yAxis: this.meanLclPoint,
                name: 'min',
                lineStyle: {
                  color: '#8A2BE2'
                },
                label: {
                  normal: {
                    formatter: `${this.meanLclPoint.toFixed(chartViewPrecisionMean)}(LCL)`
                  }
                }
              },
              {
                yAxis: this.meanClPoint,
                name: 'target',
                lineStyle: {
                  color: '#00FF00'
                },
                label: {
                  normal: {
                    formatter: `${this.meanClPoint.toFixed(chartViewPrecisionMean)}(CL)`
                  }
                }
              },
              {
                yAxis: this.meanUclPoint,
                name: 'max',
                lineStyle: {
                  color: '#8A2BE2'
                },
                label: {
                  normal: {
                    formatter: `${this.meanUclPoint.toFixed(chartViewPrecisionMean)}(UCL)`
                  }
                }
              },
              {
                yAxis: this.meanSigmaBCOverCL,
                name: 'σ',
                lineStyle: {
                  color: '#1890ff',
                  type: 'dashed'
                },
                label: {
                  normal: {
                    formatter: `${this.meanSigmaBCOverCL.toFixed(chartViewPrecisionMean)}(σ)`
                  }
                }
              },
              {
                yAxis: this.meanSigmaABOverCL,
                name: '2σ',
                lineStyle: {
                  color: '#1890ff',
                  type: 'dashed'
                },
                label: {
                  normal: {
                    formatter: `${this.meanSigmaABOverCL.toFixed(chartViewPrecisionMean)}(2σ)`
                  }
                }
              },
              {
                yAxis: this.meanSigmaBCBelowCL,
                name: 'σ',
                lineStyle: {
                  color: '#1890ff',
                  type: 'dashed'
                },
                label: {
                  normal: {
                    formatter: `${this.meanSigmaBCBelowCL.toFixed(chartViewPrecisionMean)}(σ)`
                  }
                }
              },
              {
                yAxis: this.meanSigmaABBelowCL,
                name: '2σ',
                lineStyle: {
                  color: '#1890ff',
                  type: 'dashed'
                },
                label: {
                  normal: {
                    formatter: `${this.meanSigmaABBelowCL.toFixed(chartViewPrecisionMean)}(2σ)`
                  }
                }
              }
            ]
          }
        }
      ]
    };

    if (this.meanUSpecLine > 0) {
      let meanUSpecLine = {
        yAxis: this.meanUSpecLine,
        lineStyle: { color: '#f50808' },
        label: { normal: { formatter: `${this.meanUSpecLine}(USL)` } }
      } as any;
      lineChartOption.series[0].markLine.data.push(meanUSpecLine);
      sigmaLineChartOption.series[0].markLine.data.push(meanUSpecLine);
    }

    if (this.meanLSpecLine > 0) {
      let meanLSpecLine = {
        yAxis: this.meanLSpecLine,
        lineStyle: { color: '#f50808' },
        label: { normal: { formatter: `${this.meanLSpecLine}(LSL)` } }
      } as any;
      lineChartOption.series[0].markLine.data.push(meanLSpecLine);
      sigmaLineChartOption.series[0].markLine.data.push(meanLSpecLine);
    }

    if (this.rules === 0) {
      lineChart.setOption(lineChartOption);
    } else {
      lineChart.setOption(sigmaLineChartOption);
    }

    window.addEventListener('resize', () => {
      lineChart.resize();
    });
  }

  rangeInitCharts(): void {
    const chartViewPrecisionRange = this.chartViewPrecision;
    const lineChart = this.ec.init(document.getElementById('lineChartRange'));
    const lineChartOption = {
      tooltip: {
        trigger: 'axis'
      },
      splitLine: {
        show: true
      },
      toolbox: {
        show: true
      },
      legend: {
        padding: 0
      },
      xAxis: [
        {
          type: 'category',
          data: this.rangeXdata,
          axisLabel: {
            interval: 0,
            formatter: function (value: any, index: any) {
              if (index % 2 != 0) {
                return `\n\n${value}`;
              } else {
                return value;
              }
            }
          },
          name: '',
          splitLine: {
            show: false,
            lineStyle: {
              type: 'dashed'
            }
          },
          axisLine: {
            show: true,
            symbol: ['none', 'arrow'],
            symbolOffset: 10
          },
          nameTextStyle: {
            fontWeight: 600,
            fontSize: 18
          }
        }
      ],
      yAxis: [
        {
          type: 'value',
          name: 'MR',
          splitLine: {
            show: false,
            lineStyle: {
              type: 'dashed'
            }
          },
          axisLine: {
            show: true,
            symbol: ['none', 'arrow'],
            symbolOffset: 10
          },
          axisLabel: {
            fontSize: 13,
            formatter: function (value: any, index: number) {
              return value.toFixed(chartViewPrecisionRange);
            }
          },
          max: this.rangeYMax,
          min: this.rangeYMin,
          scale: true,
          nameTextStyle: {
            fontWeight: 600,
            fontSize: 18
          }
        }
      ],
      series: [
        {
          name: '',
          showSymbol: true,
          data: this.rangeYdata,
          type: 'line',
          markLine: {
            symbol: 'none',
            lineStyle: {
              normal: {
                type: 'solid'
              }
            },
            data: [
              {
                yAxis: this.rangeLclPoint,
                name: 'min',
                lineStyle: {
                  color: '#8A2BE2'
                },
                label: {
                  normal: {
                    formatter: `${this.rangeLclPoint.toFixed(chartViewPrecisionRange)}(LCL)`
                  }
                }
              },
              {
                yAxis: this.rangeClPoint,
                name: 'target',
                lineStyle: {
                  color: '#00FF00'
                },
                label: {
                  normal: {
                    formatter: `${this.rangeClPoint.toFixed(chartViewPrecisionRange)}(CL)`
                  }
                }
              },
              {
                yAxis: this.rangeUclPoint,
                name: 'max',
                lineStyle: {
                  color: '#8A2BE2'
                },
                label: {
                  normal: {
                    formatter: `${this.rangeUclPoint.toFixed(chartViewPrecisionRange)}(UCL)`
                  }
                }
              }
            ]
          }
        }
      ]
    };

    const sigmaLineChartOption = {
      tooltip: {
        trigger: 'axis'
      },
      splitLine: {
        show: true
      },
      toolbox: {
        show: true
      },
      legend: {
        padding: 0
      },
      xAxis: [
        {
          type: 'category',
          data: this.rangeXdata,
          axisLabel: {
            interval: 0,
            formatter: function (value: any, index: any) {
              if (index % 2 != 0) {
                return `\n\n${value}`;
              } else {
                return value;
              }
            }
          },
          name: '',
          splitLine: {
            show: false,
            lineStyle: {
              type: 'dashed'
            }
          },
          axisLine: {
            show: true,
            symbol: ['none', 'arrow'],
            symbolOffset: 10
          },
          nameTextStyle: {
            fontWeight: 600,
            fontSize: 18
          }
        }
      ],
      yAxis: [
        {
          type: 'value',
          name: 'MR',
          splitLine: {
            show: false,
            lineStyle: {
              type: 'dashed'
            }
          },
          axisLine: {
            show: true,
            symbol: ['none', 'arrow'],
            symbolOffset: 10
          },
          axisLabel: {
            fontSize: 13,
            formatter: function (value: any, index: number) {
              return value.toFixed(chartViewPrecisionRange);
            }
          },
          max: this.rangeYMax,
          min: this.rangeYMin,
          scale: true,
          nameTextStyle: {
            fontWeight: 600,
            fontSize: 18
          }
        }
      ],
      series: [
        {
          name: '',
          showSymbol: true,
          data: this.rangeYdata,
          type: 'line',
          markLine: {
            symbol: 'none',
            lineStyle: {
              normal: {
                type: 'solid'
              }
            },
            data: [
              {
                yAxis: this.rangeLclPoint,
                name: 'min',
                lineStyle: {
                  color: '#8A2BE2'
                },
                label: {
                  normal: {
                    formatter: `${this.rangeLclPoint.toFixed(chartViewPrecisionRange)}(LCL)`
                  }
                }
              },
              {
                yAxis: this.rangeClPoint,
                name: 'target',
                lineStyle: {
                  color: '#00FF00'
                },
                label: {
                  normal: {
                    formatter: `${this.rangeClPoint.toFixed(chartViewPrecisionRange)}(CL)`
                  }
                }
              },
              {
                yAxis: this.rangeUclPoint,
                name: 'max',
                lineStyle: {
                  color: '#8A2BE2'
                },
                label: {
                  normal: {
                    formatter: `${this.rangeUclPoint.toFixed(chartViewPrecisionRange)}(UCL)`
                  }
                }
              },
              {
                yAxis: this.rangeSigmaBCOverCL,
                name: 'σ',
                lineStyle: {
                  color: '#1890ff',
                  type: 'dashed'
                },
                label: {
                  normal: {
                    formatter: `${this.rangeSigmaBCOverCL.toFixed(chartViewPrecisionRange)}(σ)`
                  }
                }
              },
              {
                yAxis: this.rangeSigmaABOverCL,
                name: '2σ',
                lineStyle: {
                  color: '#1890ff',
                  type: 'dashed'
                },
                label: {
                  normal: {
                    formatter: `${this.rangeSigmaABOverCL.toFixed(chartViewPrecisionRange)}(2σ)`
                  }
                }
              },
              {
                yAxis: this.rangeSigmaBCBelowCL,
                name: 'σ',
                lineStyle: {
                  color: '#1890ff',
                  type: 'dashed'
                },
                label: {
                  normal: {
                    formatter: `${this.rangeSigmaBCBelowCL.toFixed(chartViewPrecisionRange)}(σ)`
                  }
                }
              },
              {
                yAxis: this.rangeSigmaABBelowCL,
                name: '2σ',
                lineStyle: {
                  color: '#1890ff',
                  type: 'dashed'
                },
                label: {
                  normal: {
                    formatter: `${this.rangeSigmaABBelowCL.toFixed(chartViewPrecisionRange)}(2σ)`
                  }
                }
              }
            ]
          }
        }
      ]
    };
    if (this.rules === 0) {
      lineChart.setOption(lineChartOption);
    } else {
      lineChart.setOption(sigmaLineChartOption);
    }

    window.addEventListener('resize', () => {
      lineChart.resize();
    });
  }
}
